home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / NIH Image 1.62b11 / src / LeastSquares.p < prev    next >
Text File  |  1994-11-30  |  7KB  |  319 lines

  1. unit LeastSquares;
  2. {Contains the curve fitting routines based on the Simplex method described in the article " Fitting Curves to Data "}
  3. {in the May 1984 issue of Byte magazine, pages 340-362.}
  4.  
  5. interface
  6.  
  7.     uses
  8.         QuickDraw, Palettes, Printing, globals, Utilities, graphics;
  9.  
  10.  
  11.     const
  12.         nvpp = 2;
  13.         maxn = 6;
  14.         maxnp = 20;
  15.         alpha = 1.0;
  16.         beta = 0.5;
  17.         gamma = 2.0;
  18.         lw = 5;
  19.         root2 = 1.414214;
  20.         MaxError = 1e-7;
  21.  
  22.     type
  23.         ColumnVector = array[1..maxnp] of extended;
  24.  
  25.         vector = array[1..maxn] of extended;
  26.         datarow = array[1..nvpp] of extended;
  27.         index = 0..255;
  28.  
  29.  
  30.     var
  31.         m, n: integer;
  32.         done: boolean;
  33.         maxx, maxy: extended;
  34.         i, j: index;
  35.         h, l: array[1..maxn] of index;
  36.         np, npmax, niter, maxiter: integer;
  37.         next, center, smean, error, maxerr, p, q, step: vector;
  38.         simp: array[1..maxn] of vector;
  39.         data: array[1..maxnp] of datarow;
  40.         filename, newname: string;
  41.         yoffset: integer;
  42.  
  43.  
  44.     procedure DoSimplexFit (nStandards, nCoefficients: integer; xdata, ydata: ColumnVector; var Coefficients: CoefficientArray; var residuals: ColumnVector);
  45.  
  46.  
  47. implementation
  48.  
  49.  
  50.     function f (p: vector; d: datarow): extended;
  51.         var
  52.             x, y, ex: extended;
  53.     begin
  54.         x := d[1];
  55.         case info^.fit of
  56.             StraightLine: 
  57.                 f := p[1] + p[2] * x;
  58.             Poly2: 
  59.                 f := p[1] + p[2] * x + p[3] * x * x;
  60.             Poly3: 
  61.                 f := p[1] + p[2] * x + p[3] * x * x + p[4] * x * x * x;
  62.             Poly4: 
  63.                 f := p[1] + p[2] * x + p[3] * x * x + p[4] * x * x * x + p[5] * x * x * x * x;
  64.             ExpoFit: 
  65.                 f := p[1] * exp(p[2] * x);
  66.             PowerFit: 
  67.                 if x = 0.0 then
  68.                     f := 0.0
  69.                 else
  70.                     f := p[1] * exp(p[2] * ln(x)); {y=ax^b}
  71.             LogFit: 
  72.                 begin
  73.                     if x = 0.0 then
  74.                         x := 0.5;
  75.                     f := p[1] * ln(p[2] * x)
  76.                 end;
  77.             RodbardFit: 
  78.                 begin
  79.                     if x = 0.0 then
  80.                         ex := 0.0
  81.                     else
  82.                         ex := exp(ln(x / p[3]) * p[2]);
  83.                     y := p[1] - p[4];
  84.                     y := y / (1 + ex);
  85.                     f := y + p[4];
  86.                 end; {Rodbard fit}
  87.         end; {case}
  88.     end;
  89.  
  90.  
  91.     procedure order;
  92.         var
  93.             i, j: index;
  94.     begin
  95.         for j := 1 to n do
  96.             begin
  97.                 for i := 1 to n do
  98.                     begin
  99.                         if simp[i, j] < simp[l[j], j] then
  100.                             l[j] := i;
  101.                         if simp[i, j] > simp[h[j], j] then
  102.                             h[j] := i
  103.                     end
  104.             end
  105.     end;
  106.  
  107.  
  108.     procedure sum_of_residuals (var x: vector);
  109.  
  110.         var
  111.             i: index;
  112.     begin
  113.         x[n] := 0.0;
  114.         for i := 1 to np do
  115.             x[n] := x[n] + sqr(f(x, data[i]) - data[i, 2])
  116.     end;
  117.  
  118.  
  119.     procedure Initialize;
  120.         var
  121.             i, j: index;
  122.             firstx, firsty, lastx, lasty, xmean, ymean, slope, yintercept: extended;
  123.     begin
  124.         firstx := data[1, 1];
  125.         firsty := data[1, 2];
  126.         lastx := data[np, 1];
  127.         lasty := data[np, 2];
  128.         xmean := (firstx + lastx) / 2.0;
  129.         ymean := (firsty + lasty) / 2.0;
  130.         if (lastx - firstx) <> 0.0 then
  131.             slope := (lasty - firsty) / (lastx - firstx)
  132.         else
  133.             slope := 1.0;
  134.         yintercept := firsty - slope * firstx;
  135.         case info^.fit of
  136.             StraightLine: 
  137.                 begin
  138.                     simp[1, 1] := yintercept;
  139.                     simp[1, 2] := slope;
  140.                 end;
  141.             Poly2: 
  142.                 begin
  143.                     simp[1, 1] := yintercept;
  144.                     simp[1, 2] := slope;
  145.                     simp[1, 3] := 0.0;
  146.                 end;
  147.             Poly3: 
  148.                 begin
  149.                     simp[1, 1] := yintercept;
  150.                     simp[1, 2] := slope;
  151.                     simp[1, 3] := 0.0;
  152.                     simp[1, 4] := 0.0;
  153.                 end;
  154.             Poly4: 
  155.                 begin
  156.                     simp[1, 1] := yintercept;
  157.                     simp[1, 2] := slope;
  158.                     simp[1, 3] := 0.0;
  159.                     simp[1, 4] := 0.0;
  160.                     simp[1, 5] := 0.0;
  161.                 end;
  162.             ExpoFit: 
  163.                 begin
  164.                     simp[1, 1] := 0.1;
  165.                     simp[1, 2] := 0.01;
  166.                 end;
  167.             PowerFit: 
  168.                 begin
  169.                     simp[1, 1] := 0.0;
  170.                     simp[1, 2] := 1.0;
  171.                 end;
  172.             LogFit: 
  173.                 begin
  174.                     simp[1, 1] := 0.5;
  175.                     simp[1, 2] := 0.05;
  176.                 end;
  177.             RodbardFit: 
  178.                 begin
  179.                     simp[1, 1] := firsty;
  180.                     simp[1, 2] := 1.0;
  181.                     simp[1, 3] := xmean;
  182.                     simp[1, 4] := lasty;
  183.                 end;
  184.         end;
  185.         maxiter := 100 * m * m;
  186.         n := m + 1;
  187.         for i := 1 to m do
  188.             begin
  189.                 step[i] := simp[1, i] / 2.0;
  190.                 if step[i] = 0.0 then
  191.                     step[i] := 0.01;
  192.             end;
  193.         for i := 1 to n do
  194.             maxerr[i] := MaxError;
  195.         sum_of_residuals(simp[1]);
  196.         for i := 1 to m do
  197.             begin
  198.                 p[i] := step[i] * (sqrt(n) + m - 1) / (m * root2);
  199.                 q[i] := step[i] * (sqrt(n) - 1) / (m * root2)
  200.             end;
  201.         for i := 2 to n do
  202.             begin
  203.                 for j := 1 to m do
  204.                     simp[i, j] := simp[i - 1, j] + q[j];
  205.                 simp[i, i - 1] := simp[i, i - 1] + p[i - 1];
  206.                 sum_of_residuals(simp[i])
  207.             end;
  208.         for i := 1 to n do
  209.             begin
  210.                 l[i] := 1;
  211.                 h[i] := 1
  212.             end;
  213.         order;
  214.         maxx := 255;
  215.     end;
  216.  
  217.  
  218.     procedure new_vertex;
  219.         var
  220.             i: index;
  221.     begin
  222.         for i := 1 to n do
  223.             simp[h[n], i] := next[i]
  224.     end;
  225.  
  226.  
  227.     procedure DoSimplexFit (nStandards, nCoefficients: integer; xdata, ydata: ColumnVector; var Coefficients: CoefficientArray; var residuals: ColumnVector);
  228.         var
  229.             i, j: integer;
  230.             d: datarow;
  231.     begin
  232.         np := nStandards;
  233.         m := nCoefficients;
  234.         for i := 1 to np do
  235.             begin
  236.                 data[i, 1] := xdata[i];
  237.                 data[i, 2] := ydata[i];
  238.             end;
  239.         Initialize;
  240.         niter := 0;
  241.         repeat
  242.             done := true;
  243.             niter := succ(niter);
  244.             for i := 1 to n do
  245.                 center[i] := 0.0;
  246.             for i := 1 to n do
  247.                 if i <> h[n] then
  248.                     for j := 1 to m do
  249.                         center[j] := center[j] + simp[i, j];
  250.             for i := 1 to n do
  251.                 begin
  252.                     center[i] := center[i] / m;
  253.                     next[i] := (1.0 + alpha) * center[i] - alpha * simp[h[n], i]
  254.                 end;
  255.             sum_of_residuals(next);
  256.             if next[n] <= simp[l[n], n] then
  257.                 begin
  258.                     new_vertex;
  259.                     for i := 1 to m do
  260.                         next[i] := gamma * simp[h[n], i] + (1.0 - gamma) * center[i];
  261.                     sum_of_residuals(next);
  262.                     if next[n] <= simp[l[n], n] then
  263.                         new_vertex
  264.                 end
  265.             else
  266.                 begin
  267.                     if next[n] <= simp[h[n], n] then
  268.                         new_vertex
  269.                     else
  270.                         begin
  271.                             for i := 1 to m do
  272.                                 next[i] := beta * simp[h[n], i] + (1.0 - beta) * center[i];
  273.                             sum_of_residuals(next);
  274.                             if (next[n] <= simp[h[n], n]) then
  275.                                 new_vertex
  276.                             else
  277.                                 begin
  278.                                     for i := 1 to n do
  279.                                         begin
  280.                                             for j := 1 to m do
  281.                                                 simp[i, j] := (simp[i, j] + simp[l[n], j]) * beta;
  282.                                             sum_of_residuals(simp[i])
  283.                                         end
  284.                                 end
  285.                         end
  286.                 end;
  287.             order;
  288.             for j := 1 to n do
  289.                 begin
  290.                     if (simp[h[j], j] - simp[l[j], j]) = 0 then
  291.                         error[j] := 0
  292.                     else if simp[h[j], j] <> 0 then
  293.                         error[j] := (simp[h[j], j] - simp[l[j], j]) / simp[h[j], j]
  294.                     else
  295.                         error[j] := (simp[h[j], j] - simp[l[j], j]) / simp[l[j], j];
  296.                     if done then
  297.                         if abs(error[j]) > maxerr[j] then
  298.                             done := false
  299.                 end;
  300.         until (done or (niter = maxiter));
  301.         ShowMessage(concat('interations=', long2str(niter), crStr, 'max interations=', long2str(maxiter)));
  302.         for i := 1 to n do
  303.             begin
  304.                 smean[i] := 0;
  305.                 for j := 1 to n do
  306.                     smean[i] := smean[i] + simp[j, i];
  307.                 smean[i] := smean[i] / n;
  308.             end;
  309.         for i := 1 to m do
  310.             Coefficients[i] := smean[i];
  311.         for i := 1 to nstandards do
  312.             begin
  313.                 d[1] := xdata[i];
  314.                 Residuals[i] := ydata[i] - f(smean, d);
  315.             end;
  316.     end;
  317.  
  318.  
  319. end.